#include <cstdio>
#include "CommandLineParser.h"

using namespace std;

namespace tsc
{
namespace common
{

#define DEBUG(fmt, ...)
//#define DEBUG(fmt, ...) printf(fmt, ##__VA_ARGS__)

//------------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------------
CommandLineParser::CommandLineParser(int aArgCount, const char** aArgVector)
: mArgCount(aArgCount), mArgVector(aArgVector)
{
  parseCommandLine();
} // CommandLineParser::CommandLineParser

//------------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------------
CommandLineParser::~CommandLineParser()
{

} // CommandLineParser::~CommandLineParser

//------------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------------
const char* CommandLineParser::getBinaryName()
{
  return mBinaryName.data();
} // CommandLineParser::getBinaryName

//------------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------------
void CommandLineParser::parseCommandLine() throw(ios_base::failure)
{
  int    argIdx = 1;
  string temp;
  bool   isKeyFound = false;
  bool   isValFound = false;
  string key;
  string val;
  string errorMsg("CommandLineParser::parseCommandLine() ");

  mBinaryName = mArgVector[0];

  while (argIdx < mArgCount)
  {
    temp = mArgVector[argIdx];
    DEBUG("argv[%d] = %s\n",argIdx, temp.data());
    if (argIdx == 1) // first parameter must be a key
    {
      DEBUG("argIdx == 1\n");
      if (temp[0] == '-')
      {
        DEBUG("temp[0] == '-'\n");
        if (temp[1] == '-') // long name eg. "--switch"
        {
          key = temp.data() + 2;
          DEBUG("temp[1] == '-', key=%s\n",key.data());
        }
        else // short name eg "-s"
        {
          if (temp[2] == 0)
          {
            key = temp.data() + 1;
            DEBUG("temp[2] == 0, key=%s\n",key.data());
          }
          else
          {
            DEBUG("temp[2] != ' ', EXC\n");
            errorMsg.append("Short type switch requires a single character instead of '"+temp+"'.\n");
            ios_base::failure exc(errorMsg);
            throw exc;
          }
        }
        isKeyFound = true;
      }
      else // temp[0] != '-'
      {
        DEBUG("temp[0] != ' ', EXC\n");
        errorMsg.append("First argument must be a parameter switch, got '" + temp + "' instead\n");
        ios_base::failure exc(errorMsg);
        throw exc;
      }
    }
    else // argIdx != 1
    {
      DEBUG("argIdx != 1, argIdx=%d\n",argIdx);
      if (temp[0] == '-')
      {
        DEBUG("temp[0] == '-'\n");
        if (temp[1] == '-') // long name eg. "--switch"
        {
          key = temp.data() + 2;
          DEBUG("temp[1] == '-', key=%s\n",key.data());
        }
        else // short name eg "-s"
        {
          if (temp[2] == 0)
          {
            key = temp.data() + 1;
            DEBUG("temp[2] == 0, key=%s\n",key.data());
          }
          else
          {
            DEBUG("temp[2] != ' ', EXC\n");
            errorMsg.append("Short type switch requires a single character instead of '"+temp+"'.\n");
            ios_base::failure exc(errorMsg);
            throw exc;
          }
        }
        isKeyFound = true;
      }
      else // temp[0] != '-'
      {
        DEBUG("temp[0] != '-'\n");
        if (isKeyFound)
        {
          DEBUG("isKeyFound == true\n");
          val = temp;
          isValFound = true;
        }
        else
        {
          DEBUG("isKeyFound == false, EXC\n");
          errorMsg.append("Parameter of value " + temp + " has no parameter switch defined.\n");
          ios_base::failure exc(errorMsg);
          throw exc;
        }
      }
    }

    // if next parameter is a key then this one has no value
    if ((!isValFound) && (argIdx+1 < mArgCount) && (mArgVector[argIdx+1][0] == '-'))
    {
      DEBUG("Next arg is a switch, Value is empty.\n");
      val        = "";
      isValFound = true;
    }
    if ((!isValFound) && (argIdx+1 == mArgCount))
    {
      DEBUG("Last arg is a switch, Value is empty.\n");
      val        = "";
      isValFound = true;
    }

    // check for duplicates and add
    if (isKeyFound && isValFound)
    {
      DEBUG("isKeyFound == true, isValFound == true\n");
      if (!isKeyPresent(key))
      {
        DEBUG("Key=%s not present\n", key.data());
        mKeyValMap.insert(std::pair<std::string, std::string>(key, val));
      }
      else
      {
        DEBUG("Key=%s present. EXC\n",key.data());
        errorMsg.append("Option '" + key + "' has already been used.\n");
        ios_base::failure exc(errorMsg);
        throw exc;
      }

      isKeyFound = false;
      isValFound = false;
    }
    ++argIdx;
  }

} // CommandLineParser::parseCommandLine

} // namespace common
} // namespace tsc
